﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MobileCarManager.MobileControls.Styles;
using OpenNETCF.GDIPlus;

namespace MobileCarManager.MobileControls
{
  public class StyleButton : System.Windows.Forms.Control
  {
    /// <summary>States of the button.</summary>
    private enum ButtonState
    {
      /// <summary>Default state of a button (button is released).</summary>
      Normal = 0,
      /// <summary>Button is pressed.</summary>
      Pressed
    };
    private ButtonState _buttonState = ButtonState.Normal;

    public StyleButton()
    {
    }

    /// <summary>Returns the root element of a button style.</summary>
    private MobileCarManager.MobileControls.Styles.ButtonStyle Styles
    {
      get { return StyleManager.Instance.Styles.Button; }
    }

    /// <summary>Handler for the mouse down event.</summary>
    protected override void OnMouseDown(MouseEventArgs e)
    {
      base.OnMouseDown(e);
      _buttonState = ButtonState.Pressed;
      Invalidate();
    }

    /// <summary>Handler for the mouse up event.</summary>
    protected override void OnMouseUp(MouseEventArgs e)
    {
      base.OnMouseUp(e);
      _buttonState = ButtonState.Normal;
      Invalidate();
    }

    protected override void OnPaintBackground(PaintEventArgs e)
    {
      //base.OnPaintBackground(e);
    }

    protected override void OnPaint(PaintEventArgs pe)
    {
      Bitmap bmp = new Bitmap(ClientSize.Width, ClientSize.Height);
      Graphics gfx = Graphics.FromImage(bmp);
      DrawBackground(gfx);
      DrawBorder(gfx);
      DrawText(gfx);
      pe.Graphics.DrawImage(bmp, 0, 0);
      base.OnPaint(pe);
    }

    /// <summary>Draws the text of the button.</summary>
    private void DrawText(Graphics g)
    {
      SizeF size = g.MeasureString(this.Text, Styles.Font);
      using (Brush brush = new SolidBrush(Styles.TextColor))
        g.DrawString(this.Text, Styles.Font, brush, new RectangleF((Width - size.Width) / 2.0f, (Height - size.Height) / 2.0f, size.Width, size.Height));
    }

    /// <summary>Draws the background of the button.</summary>
    private void DrawBackground(Graphics graphics)
    {
      // Border-Width is needed to calculate the background area.
      int borderWidth = Styles.Border.Width;

      // Get the colors of the background.
      Color[] colors = Styles.BackgroundGradient.Gradient.ToArray();

      // If the button is pressed, we paint it a bit darker.
      if (_buttonState == ButtonState.Pressed)
      {
        const int darkness = 15;
        for (int index = 0; index < colors.Length; ++index)
        {
          int r = (colors[index].R < darkness) ? 0 : colors[index].R - darkness;
          int g = (colors[index].G < darkness) ? 0 : colors[index].G - darkness;
          int b = (colors[index].B < darkness) ? 0 : colors[index].B - darkness;
          colors[index] = Color.FromArgb(r, g, b);
        }
      }
      // TODO: Accept dynamic color count.
      IntPtr hdc = graphics.GetHdc();
      using (LinearGradientBrush upperBrush = new LinearGradientBrush(new GpPointF(1, 1), new GpPointF(1, (this.Height - 2) / 2), colors[0], colors[1]))
      using (LinearGradientBrush lowerBrush = new LinearGradientBrush(new GpPointF(1, (this.Height - 2) / 2), new GpPointF(1, (this.Height - 1)), colors[1], colors[2]))
      using (GraphicsPlus gp = new GraphicsPlus(hdc))
      {
        gp.FillRectangle(lowerBrush, new GpRect(borderWidth, (this.Height / 2) - 1, this.Width - (2 * borderWidth), (this.Height / 2) - borderWidth + 2));
        gp.FillRectangle(upperBrush, new GpRect(borderWidth, borderWidth, this.Width - (2 * borderWidth), (this.Height / 2) - borderWidth));
      }
      graphics.ReleaseHdc(hdc);
    }

    /// <summary>Draws the border of the button.</summary>
    private void DrawBorder(Graphics g)
    {
      int borderWidth = Styles.Border.Width;
      g.DrawRectangle(new Pen(Styles.Border.Color, (float)borderWidth),
        borderWidth / 2, borderWidth / 2, Width - borderWidth, Height - borderWidth);
    }
  }
}
